﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConnectFour
{
    class TylerPlayer: Player
    {
        List<Line> lines = new List<Line>();
        int[] lastRows = new int[7];
        public TylerPlayer(Checker myColor, Board board)
            : base(myColor, board, null)
        {
            for (int i = 0; i < 6; i++)
            {
                for (int j = 0; j < 7; j++)
                {
                    if (j < 4)
                        lines.Add(new Line(i, j, Direction.Horizontal, this));

                    if (i < 3)
                        lines.Add(new Line(i, j, Direction.Vertical, this));

                    if (j < 4 && i < 3)
                        lines.Add(new Line(i, j, Direction.DiagUp, this));

                    if(j < 4 && i > 2)
                        lines.Add(new Line(i, j, Direction.DiagDown, this));
                }
            }
        }

        public override void GameOver(Checker winner) { }

        public override int Move(int lastMove)
        {
            int[] scores = new int[7];
            int maxScore = Int32.MinValue, maxScoreCol = -1;
            for (int i=0; i<lines.Count; i++)
            {
                lines[i].ScoreLine(ref scores, lastMove == -1 ? 0 : lastRows[lastMove], lastMove);
                if (lines[i].DeadLine)
                {
                    lines.RemoveAt(i);
                    i--;
                }
            }

            for (int i = 0; i < 7; i++)
            {
                if (board.Playable(i))
                {
                    scores[i]++;
                }
                else
                {
                    scores[i] = int.MinValue;
                }
                if (scores[i] > maxScore)
                {
                    maxScore = scores[i];
                    maxScoreCol = i;
                }
            }
            Console.WriteLine("{0} {1} {2} {3} {4} {5} {6}", scores[0], scores[1], scores[2], scores[3], scores[4], scores[5], scores[6]);
            return maxScoreCol;
        }
    }

    class Line
    {
        private Direction dir;
        private TylerPlayer player;
        private int[,] locs = new int[4, 2]; //column, row
        private bool[] interestedRows = new bool[6], interestedColumns = new bool[7];
        private bool dead = false;

        public bool DeadLine
        {
            get
            {
                return dead;
                /*return ((player.Board[locs[0, 1], locs[0, 0]] | player.Board[locs[1, 1], locs[1, 0]] |
                    player.Board[locs[2, 1], locs[2, 0]] | player.Board[locs[3, 1], locs[1, 0]]) & Checker.Color) == Checker.Color;*/
            }
        }

        public Line(int startRow, int startCol, Direction dir, TylerPlayer player){
            int dCol = (dir == Direction.Vertical ? 0 : 1);
            int dRow = (dir == Direction.Horizontal ? 0 : (dir == Direction.DiagDown ? -1 : 1));
            this.dir = dir;
            this.player = player;
            for (int i = 0; i < 4; i++)
            {
                locs[i, 0] = startCol + i * dCol;
                interestedColumns[locs[i, 0]] = true;
                locs[i, 1] = startRow + i * dRow;
                interestedRows[locs[i, 1]] = true;
            }
        }

        public void ScoreLine(ref int[] scores, int lastRow, int lastColumn){
            int mine = 0, opponent = 0, playable = 0;
            bool[] playableCols = new bool[7];
            Checker check;

            //Rule 1 - if red and black in this line, it's now useless. 
            for (int i = 0; i < 4; i++)
            {
                check = player.Board[locs[i,1], locs[i,0]] & Checker.Color;
                if (check == player.Checker)
                    mine++;
                if (check == player.OpponentChecker)
                    opponent++;
            }
            if (mine > 0 && opponent > 0)
            {
                dead = true;
                return;
            }

            //Rule 2 - give every column 1 point for any line it contributes to if it can actually be played in
            for (int i = 0; i < 4; i++)
            {
                if (player.Board.Playable(locs[i,0]) && player.Board.NextRow(locs[i, 0]) == locs[i, 1])
                {
                    scores[locs[i, 0]] += 1 + mine;
                    playable++;
                    playableCols[locs[i, 0]] = true;
                }
            }

            //rule 3 - if either player has 3 in a row, GO THERE if it can be played in
            //rule 4 - if it can't be played in, but the column under it can, score the column down
            if (mine == 3 || opponent == 3)
            {
                for (int i = 0; i < 4; i++)
                {
                    //rule 3
                    if (/*(player.Board[locs[i, 1], locs[i, 0]] & Checker.Color) == Checker.Empty && 
                        (player.Board.Playable(locs[i,0]) && player.Board.NextRow(locs[i, 0]) == locs[i, 1])*/ playableCols[locs[i,0]])
                    {
                        scores[locs[i, 0]] += 2*short.MaxValue;
                    }

                    //rule 4
                    if (locs[i, 1] > 0 && (player.Board[locs[i, 1] - 1, locs[i, 0]] & Checker.Color) == Checker.Empty &&
                        player.Board.Playable(locs[i, 0]) && player.Board.NextRow(locs[i, 0]) == locs[i, 1]-1)
                    {
                        if (scores[locs[i, 0]] >= 0)
                        {
                            scores[locs[i, 0]] -= short.MaxValue;
                        }
                    }
                }
            }

            //rule 5 - if either player has 2 in a line, and the other two are playable, score that line higher, unless it's vertical
            if (dir != Direction.Vertical && playable == 2 && (mine == 2 || opponent == 2))
            {
                for (int i = 0; i < 4; i++)
                {
                    if (playableCols[locs[i, 0]])
                    {
                        scores[locs[i, 0]] += short.MaxValue;
                    }
                }
            }
        }
    }

    enum Direction{
        Horizontal, Vertical, DiagUp, DiagDown
    }
}
